<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3. 影响 webgl 性能的要素</title>
    <style>
        canvas{
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas width="512" height="512"></canvas>

    <script type="module">
        import { Renderer, Camera, Transform, Program, Mesh, Geometry } from '/common/lib/ogl/index.mjs';
        
        // 批量生成几何体图形（实例化渲染）
        function circleGeometry(gl, radius = 0.4, count = 30000, segments = 20){
            const tau = Math.PI * 2;
            const position = new Float32Array(segments * 2 + 2); // 分成segments片，还需要加上几何体的图形中心坐标
            const index = new Uint16Array(segments * 3); // 一个片段包含三个顶点
            const id = new Uint16Array(count);

            // 处理顶点集合
            for (let i = 0; i < segments; i++) {
                // 计算分片的弧度
                const alpha = i / segments * tau;
                // 计算每个分片的新坐标，并加入顶点集合中，从索引2开始插入
                position.set([radius * Math.cos(alpha), radius * Math.sin(alpha)], i * 2 + 2);
            }
            // 处理三角剖分的顶点索引集合
            for (let i = 0; i < segments; i++) {
                if(i == segments - 1){// 处理收尾相接的情况
                    index.set([0, i + 1, 1], i * 3);
                }else{
                    index.set([0, i + 1, i + 2], i * 3);
                }
            }
            for (let i = 0; i < count; i++) {
                id.set([i], i);
            }

            return new Geometry(gl, {
                position: { data: position, size: 2, }, 
                index: { data: index, }, 
                // 传递带有 instanced 属性的顶点数据，就可以自动使用 instanced drawing 技术来批量绘制图形
                // InstancedDrawing（实例化渲染）
                id: { instanced: 1, size: 1, data: id, }, 
            });
        }

        let canvas = document.querySelector("canvas");
        // 1. 创建画布宽高512的renderer对象
        const renderer = new Renderer({
            canvas,
            width:512,
            height:512
        });

        const gl = renderer.gl;
        gl.clearColor(1, 1, 1, 1);

        // 2. 创建相机

        // 3. 创建场景
        const scene = new Transform();

        // 4. 创建几何体对象

        // 5. 创建webgl程序
        const vertex = `
            precision highp float;

            attribute vec2 position;
            attribute float id;
            uniform float uTime;

            highp float random(vec2 co) {
                highp float a = 12.9898;
                highp float b = 78.233;
                highp float c = 43758.5453;
                highp float dt= dot(co.xy ,vec2(a,b));
                highp float sn= mod(dt,3.14);
                return fract(sin(sn) * c);
            }

            vec3 hsb2rgb(vec3 c){
                vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), 6.0)-3.0)-1.0, 0.0, 1.0);
                rgb = rgb * rgb * (3.0 - 2.0 * rgb);
                return c.z * mix(vec3(1.0), rgb, c.y);
            }

            varying vec3 vColor;

            void main() {
                vec2 offset = vec2(
                    1.0 - 2.0 * random(vec2(id + uTime, 100000.0)),
                    1.0 - 2.0 * random(vec2(id + uTime, 200000.0))
                );
                vec3 color = vec3(
                    random(vec2(id + uTime, 300000.0)),
                    1.0,
                    1.0
                );
                vColor = hsb2rgb(color);
                gl_Position = vec4(position + offset, 0.0, 1.0);
            }
        `;
        const fragment = `
            precision highp float;

            varying vec3 vColor;

            void main() {
                gl_FragColor = vec4(vColor, 1.0);  
            }
        `;

        const program = new Program(gl, {
            vertex,
            fragment,
            uniforms:{
                uTime: { value: 0 },
            }
        });

        // 6. 创建网格对象
        const geometry = circleGeometry(gl, 0.05);
        const mesh = new Mesh(gl, {
            geometry,
            program,
            mode: gl.TRIANGLE
        });
        mesh.setParent(scene);

        // 7. 渲染
        requestAnimationFrame(update);
        function update(t) {
            requestAnimationFrame(update);
            program.uniforms.uTime.value = t * 0.0002;
            renderer.render({ scene });
        }

    </script>
</body>
</html>